package hikari.gui.panels;

import com.gooddies.swing.VerticalLayout;
import com.gooddies.wiring.Wiring;
import com.gooddies.wiring.annotations.WiringComponent;
import hikari.gui.guicomponents.ExpandablePanel;
import hikari.gui.panels.BasicObjectPropertiesPanel.UPDATE_TYPE;
import hikari.hcomponents.HComponent;
import hikari.hcomponents.RenderEvent;
import hikari.managers.SelectionManager;
import hikari.objects3d.Basic3dObject;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;

/**
 * @author Dmitry
 */
@WiringComponent(singleton = true, lazy = true)
public class ModifyPanel extends JPanel {

    private JScrollPane scrollPane;
    private BasicObjectPropertiesPanel basicPropertiesPanel;
    private List<HComponent> panels;
    public List<RenderEvent> afterRenderBeforeGUIEvents = new ArrayList<>();
    public List<RenderEvent> afterRenderEvents = new ArrayList<>();
    public List<RenderEvent> beforeRenderEvents = new ArrayList<>();
    private Basic3dObject currentObject = null;

    private ModifyPanel() {
    }

    public void init(JScrollPane scrollPane) {
        this.scrollPane = scrollPane;
        setLayout(new VerticalLayout().setBetweenGap(3));

        Wiring.getComponent(SelectionManager.class).addSelectionEvent(new SelectionManager.SelectionEvent() {
            @Override
            public void onSelected(Basic3dObject currentSelection, Basic3dObject newSelection) {
                onSelect(currentSelection, newSelection);
            }

            @Override
            public boolean isCanSelect(Basic3dObject currentSelection, Basic3dObject newSelection) {
                return true;
            }
        });
    }

    private void onSelect(Basic3dObject currentSelection, Basic3dObject newSelection) {
        clearModifyPanel();
        if (newSelection != null) {
            fillModifyPanel(newSelection);
        }
    }

    private void fillModifyPanel(Basic3dObject object) {
        currentObject = object;
        basicPropertiesPanel = Wiring.getComponent(BasicObjectPropertiesPanel.class);
        basicPropertiesPanel.fillFields(object, UPDATE_TYPE.ALL);
        add(basicPropertiesPanel);
        panels = object.getEditPanels();
        for (HComponent panel : panels) {
            RenderEvent renderEvent = panel.registerAfterRenderBeforeGuiEvent();
            if (renderEvent != null) {
                afterRenderBeforeGUIEvents.add(renderEvent);
            }
            renderEvent = panel.registerAfterRenderEvent();
            if (renderEvent != null) {
                afterRenderEvents.add(renderEvent);
            }
            renderEvent = panel.registerBeforeRenderEvent();
            if (renderEvent != null) {
                beforeRenderEvents.add(renderEvent);
            }
            registerPopupMenuOnPanel(panel);
            add(panel);
        }
        updateScroll();
    }

    private JMenuItem createDeleteComponentMenuItem(final HComponent component) {
        JMenuItem menuItem = new JMenuItem("Delete Component");
        menuItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (currentObject != null) {
                    component.onDeleteComponent();
                    remove(component);
                    currentObject.removeHComponent(component);
                    updateScroll();
                }
            }
        });
        return menuItem;
    }

    private void registerPopupMenuOnPanel(HComponent component) {
        JMenuItem[] menus = component.submitPopupMenuItems();
        if (menus.length == 0 && !component.isDeleteable()) {
            return;
        }
        JPopupMenu menu = new JPopupMenu();
        for (JMenuItem item : menus) {
            menu.add(item);
        }
        if (component.isDeleteable()) {
            menu.add(createDeleteComponentMenuItem(component));
        }
        component.setInheritsPopupMenu(true);
        component.setComponentPopupMenu(menu);
    }

    public void updateTransformationData(UPDATE_TYPE type) {
        basicPropertiesPanel.updatePanelData(type);
    }

    public void updateScroll() {
        invalidate();
        validate();
        repaint();
        scrollPane.invalidate();
        scrollPane.validate();
        scrollPane.repaint();
    }

    @Override
    public void invalidate() {
        super.invalidate();
        for (int i = 0; i < getComponentCount(); i++) {
            Object o = getComponent(i);
            if (o instanceof ExpandablePanel) {
                ExpandablePanel panel = (ExpandablePanel) o;
                panel.setPreferredSize(new Dimension(getWidth() - 20, panel.getPreferredSize().height));
            }
        }
    }

    public void clearModifyPanel() {
        if (panels != null) {
            for (HComponent panel : panels) {
                panel.onClose();
            }
            panels.clear();
        }
        currentObject = null;
        afterRenderBeforeGUIEvents.clear();
        afterRenderEvents.clear();
        beforeRenderEvents.clear();
        removeAll();
        invalidate();
        validate();
        repaint();
    }

    public void reFillPanel() {
        Basic3dObject temp = currentObject;
        clearModifyPanel();
        if (temp != null) {
            fillModifyPanel(temp);
        }
    }

    public void fillPanelWith3dObjectData(Basic3dObject object) {
        clearModifyPanel();
    }

    public void onAfterRenderBeforeGui() {
        for (RenderEvent rEvent : afterRenderBeforeGUIEvents) {
            rEvent.onRender();
        }
    }

    public void onAfterRender() {
        for (RenderEvent rEvent : afterRenderEvents) {
            rEvent.onRender();
        }
    }

    public void onBeforeRender() {
        for (RenderEvent rEvent : beforeRenderEvents) {
            rEvent.onRender();
        }
    }
}
